/*
 * Created by Huang 嵘才 on 18-5-8 上午10:07
 * Copyright (c) 2018. All rights reserved.
 * Last modified 18-5-8 上午10:07
 */

package io.esirong.widget.view;

import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.AttributeSet;

import java.util.Calendar;
import java.util.TimeZone;

import androidx.appcompat.widget.AppCompatTextView;

/**
 * TextClock
 * Created by 黄嵘才(HuangRc) on 2018/5/8.
 */

public class TextClockView extends AppCompatTextView {

    public static final CharSequence DEFAULT_FORMAT_24_HOUR = "H:mm";
    public static final int FORMAT_12 = 0;
    public static final int FORMAT_24 = 1;
    public static final int FORMAT_AUTO = 2;
    private static final CharSequence LocaleData_timeFormat_hm = "h:mm";
    private static final CharSequence LocaleData_timeFormat_kkm = "kk:mm";
    private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
        }
    };
    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        }
    };
    private boolean mAttached;
    private boolean mHasSeconds;
    private Calendar mTime;
    private ClockOscillator mTicker;
    private CharSequence mFormat;
    private CharSequence mDescFormat;
    private CharSequence mFormat12;
    private CharSequence mFormat24;
    private CharSequence mDescFormat12;
    private CharSequence mDescFormat24;
    private int forceUse = FORMAT_AUTO;
    private String mTimeZone;

    public TextClockView(Context context) {
        this(context, null);
    }

    public TextClockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TextClockView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * Returns a if not null, else return b if not null, else return c.
     */
    private static CharSequence abc(CharSequence a, CharSequence b, CharSequence c) {
        return a == null ? (b == null ? c : b) : a;
    }

    private void init() {
        mHasSeconds = true;
        createTime(mTimeZone);
        chooseFormat(false);
        setText(DateFormat.format(mFormat, mTime));
    }

    private void createTime(String timeZone) {
        if (timeZone != null) {
            mTime = Calendar.getInstance(TimeZone.getTimeZone(timeZone));
        } else {
            mTime = Calendar.getInstance();
        }
    }

    private void chooseFormat(boolean handleTicker) {
        final boolean format24Requested = is24HourModeEnabled();
        if (format24Requested) {
            mFormat = abc(mFormat24, mFormat12, LocaleData_timeFormat_kkm);
            mDescFormat = abc(mDescFormat24, mDescFormat12, mFormat);
        } else {
            mFormat = abc(mFormat12, mFormat24, LocaleData_timeFormat_hm);
            mDescFormat = abc(mDescFormat12, mDescFormat24, mFormat);
        }
    }

    public boolean is24HourModeEnabled() {
        if (forceUse == FORMAT_12) {
            return false;
        } else if (forceUse == FORMAT_24) {
            return true;
        }

        return DateFormat.is24HourFormat(getContext());
    }

    private void onTimeChanged() {
        mTime.setTimeInMillis(System.currentTimeMillis());
        setText(DateFormat.format(mFormat, mTime));
        setContentDescription(DateFormat.format(mDescFormat, mTime));
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (!mAttached) {
            mAttached = true;
            registerTimeTicker();
            createTime(mTimeZone);
            if (mHasSeconds) {
                mTicker.tick();
            } else {
                onTimeChanged();
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mAttached) {
            unregisterTimeTicker();
            mAttached = false;
        }
    }

    private void registerTimeTicker() {
        registerReceiver();
        registerObserver();
        mTicker = new ClockOscillator(getContext());
        mTicker.start();
        mTicker.setOnTickListener(new ClockOscillator.OnTickListener() {
            @Override
            public void onTick(ClockOscillator countDownTimer) {
                onTimeChanged();
            }

            @Override
            public void onComplete(ClockOscillator countDownTimer) {

            }
        });
    }

    private void unregisterTimeTicker() {
        unregisterReceiver();
        unregisterObserver();
        mTicker.stop();
        mTicker = null;
    }

    private void registerReceiver() {
        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_TIME_TICK);
        filter.addAction(Intent.ACTION_TIME_CHANGED);
        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
        getContext().registerReceiver(mIntentReceiver, filter, null, getHandler());
    }

    private void registerObserver() {
        final ContentResolver resolver = getContext().getContentResolver();
        resolver.registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);
    }

    private void unregisterReceiver() {
        getContext().unregisterReceiver(mIntentReceiver);
    }

    private void unregisterObserver() {
        final ContentResolver resolver = getContext().getContentResolver();
        resolver.unregisterContentObserver(mFormatChangeObserver);
    }
}
